#########################################################################################
# Package       Wx::Perl::SimpleThread::Timer
# Description:  Wx::Timer Class
# Created       Mon Mar 29 18:47:40 2010
# SVN Id        $Id: Timer.pm 5 2010-03-30 09:55:07Z mark.dootson $
# Copyright:    Copyright (c) 2010 Mark Dootson
# Licence:      This program is free software; you can redistribute it 
#               and/or modify it under the same terms as Perl itself
#########################################################################################

package Wx::Perl::SimpleThread::Timer;

#########################################################################################

use strict;
use warnings;
use Wx;
use Wx::Timer;
use base qw( Wx::Timer );

our $VERSION = '0.02';

sub DESTROY {
    my $self = shift;
    
    ## clear any live procs
    for my $ref (@{ $self->{_handlers} }) {
        if( my $handler = $ref->get_handler ) {
            $handler->join_thread(-5);
        }
    }       
    $self->SUPER::DESTROY if $self->can("SUPER::DESTROY");
}

sub new {
    my $self = shift->SUPER::new(@_);
    $self->{_handlers} = [];
    $self->{_pollinterval} = 100;
    return $self;
}

sub _set_poll_interval {
    my $self = shift;
    $self->{_pollinterval} = shift;
    if($self->IsRunning()) {
        $self->Stop();
        $self->Start( $self->{_pollinterval} );
    }
}

sub Notify {
    my ($self ) = @_;
    return 1 if($self->{_notify_in_progress}); # do not re-enter notify proc
    $self->{_notify_in_progress} = 1;
        
    my @checkhandlers = @{ $self->{_handlers} };
    my $maxdata = 100;
    
    for my $href (@checkhandlers) {
        my $handler = $href->get_handler;
        next if !$handler;
        
        # cleanup non running threads
        if(!$handler->is_thread_running) {
            
            $self->_remove_handler( $handler );
            next;
        }
        # handle data
        my $tid = $handler->tid;
        my $datacount = 0;
        while(defined(my $data = $handler->_read_thread) ) {
            $datacount ++;
            if((ref($data) eq 'HASH') && exists($data->{_wxpst_return_type})) {
                if( $data->{_wxpst_return_type} eq 'exit') {
                    $handler->join_thread;
                    $self->_remove_handler( $handler );
                    $handler->on_thread_exit_event();
                } elsif( $data->{_wxpst_return_type} eq 'started') {
                    $handler->_set_busy_status(1);
                } elsif( $data->{_wxpst_return_type} eq 'finished') {
                    $handler->_set_busy_status(0);
                    $handler->on_thread_request_complete($data->{_wxpst_return_data});
                }
            } else {
                $handler->on_thread_data_event($data);
            }
            last if $datacount > $maxdata;
        }   
    }
    
    $self->{_notify_in_progress} = 0;
    $self->Stop() unless( $self->HandlerCount  );
    return 1;
}

sub Start {
    my $self = shift;
    my @args = @_;
    $self->SUPER::Start(@args);   
}

sub Stop {
    my $self = shift;
    $self->SUPER::Stop();   
}

sub _add_handler {
    my ($self, $handler) = @_;
    my $href = Wx::Perl::SimpleThread::Timer::Href->new($handler);
    push(@{ $self->{_handlers} }, $href );
    $self->Start($self->{_pollinterval}) if(!$self->IsRunning());
}

sub _remove_handler {
    my($self, $href) = @_;
    my $checktid = $href->tid;
    my @oldthreads = @{ $self->{_handlers} };
    my @newthreads = ();
    for ( @oldthreads ) {
        push(@newthreads, $_) if $_->tid != $checktid;
    }
    $self->{_handlers} = \@newthreads;
}

sub HandlerCount {
    my $self = shift;
    return scalar @{ $self->{_handlers} };
}

package Wx::Perl::SimpleThread::Timer::Href;
use strict;
use warnings;
use Scalar::Util qw( weaken isweak );
our $VERSION = '0.02';

sub new {
    my($class, $handler) = @_;
    my $self = bless {}, $class;
    $self->{tid} = $handler->tid;
    $self->{href} = $handler;
    weaken $self->{href};
    return $self;
}

sub tid { $_[0]->{tid}; }

sub get_handler {
    my $self = shift;
    if(isweak $self->{href}) {
        my $handler = $self->{href};
        return $handler;
    } else {
        Wx::Perl::SimpleThread::_remove_thread_handler($self);
        return undef;
    }
}


1;
